﻿// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

D3DPRESENT_PARAMETERS   g_present;

HWND                    g_hWnd = NULL;
IDirect3D9* g_Direct3D9 = NULL;
IDirect3DDevice9* g_pd3dDevice = NULL;

Reset_t                 oReset;
WndProc_t               oWndProc;
EndScene_t              oEndScene;

Reset_t                 oldResetAdrs;
EndScene_t              oldEndSceneAdrs;

bool mainBeginSate = TRUE;
bool tab_bar_flags = TRUE;


#ifdef _WIN64
#define SELF_PTR LONG_PTR
#define WNDPROC_INDEX GWLP_WNDPROC
#else
#define SELF_PTR int
#define WNDPROC_INDEX GWL_WNDPROC
#endif

// ImGui初始化，此处只执行一次
void initImguiRender(IDirect3DDevice9* pd3dDevice)
{
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    io.ConfigFlags = ImGuiConfigFlags_NoMouseCursorChange;
    io.WantSaveIniSettings = false;
    io.IniFilename = NULL;

    //ImGuiStyle& style = ImGui::GetStyle();

    //ImGui::StyleColorsDark();
    ImGui::StyleColorsClassic();
    //ImGui::StyleColorsLight();
    //LoadMyStype();

    ImFontConfig f_cfg;
    f_cfg.FontDataOwnedByAtlas = false;
    const ImFont* font = io.Fonts->AddFontFromMemoryTTF((void*)baidu_font_data, baidu_font_size, 14.0f, &f_cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());

    ImGui_ImplWin32_Init(g_hWnd);
    ImGui_ImplDX9_Init(pd3dDevice);
}

// 窗口消息处理，获取窗口操作消息转嫁给IMGUI
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT __stdcall hkWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam)) return true;
    return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam);
}

// HOOK后执行-> 重置函数
HRESULT __stdcall hkReset(IDirect3DDevice9* pd3dDevice, D3DPRESENT_PARAMETERS* pPresentationParameters)
{
    //printf("我进来了！=> hkReset \n");
    Helpers::UnHookFunction((PVOID*)(&oldResetAdrs), hkReset);

    //HRESULT WINAPI hkReset(IDirect3DDevice9* pd3dDevice, D3DPRESENT_PARAMETERS* pPresentationParameters)
    ImGui_ImplDX9_InvalidateDeviceObjects();
    HRESULT tmpReset = pd3dDevice->Reset(pPresentationParameters);
    ImGui_ImplDX9_CreateDeviceObjects();
    Helpers::HookFunction((PVOID*)(&oldResetAdrs), hkReset);
    return tmpReset;
}

// HOOK后执行-> 结束绘制函数
HRESULT __stdcall hkEndScene(IDirect3DDevice9* pd3dDevice)
{
    static bool firstCall = TRUE;
    if (firstCall)
    {
        firstCall = FALSE;
        initImguiRender(pd3dDevice);
        oWndProc = (WNDPROC)SetWindowLongPtr(g_hWnd, WNDPROC_INDEX, (LONG_PTR)hkWndProc);
    }
    Helpers::UnHookFunction((PVOID*)(&oldEndSceneAdrs), hkEndScene);

    // 界面开始绘制
    ImGui_ImplDX9_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    // 窗口大小
    ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
    ImGui::SetNextWindowSize(ImVec2(350, 450));

    ImGui::Begin(u8"剑灵2 - SCRIPT", &mainBeginSate);

    if (ImGui::BeginTabBar(u8"mytab", tab_bar_flags))
    {
        if (ImGui::BeginTabItem(u8"SCRIPT - 功能"))
        {
            //ImGui::Checkbox(u8"UP", &g_upGod);
            //ImGui::SameLine();
            //ImGui::Checkbox(u8"DOWN", &g_DownIn);
            if (ImGui::CollapsingHeader(u8"SCRIPT = 简介"))
            {
                ImGui::Text(u8"SCRIPT说明:");
                ImGui::BulletText(u8" - 第一步打开SCRIPT目录；");
                ImGui::BulletText(u8" - 第二步双击exe程序；");
                ImGui::Text(u8"SCRIPT说明：");
                ImGui::BulletText(u8" - 卧室嫩爹！");
                ImGui::BulletText(u8" - SUPER反弹！");
                ImGui::Text(u8"最后说明!");
            }
            ImGui::EndTabItem();
        }

        /*================================================================*/

        if (ImGui::BeginTabItem(u8"SCRIPT - 简介"))
        {
            ImGui::Text(u8"这里是2的内容");
            if (ImGui::CollapsingHeader(u8"SCRIPT = 简介"))
            {
                ImGui::Text(u8"SCRIPT说明1:");
                ImGui::BulletText(u8" - 第一步打开SCRIPT目录；");
                ImGui::BulletText(u8" - 第二步双击exe程序；");

                ImGui::Text(u8"SCRIPT说明2：");
                ImGui::BulletText(u8" - 卧室嫩爹！");
                ImGui::BulletText(u8" - SUPER反弹！");
                ImGui::Text(u8"最后说明!");
            }
            ImGui::EndTabItem();
        }

        /*================================================================*/

        if (ImGui::BeginTabItem(u8"SCRIPT - 世界"))
        {
            ImGui::Text(u8"这里是【3】的内容");
            if (ImGui::CollapsingHeader(u8"SCRIPT = 简介"))
            {
                ImGui::Text(u8"SCRIPT说明:");
                ImGui::BulletText(u8" - 第一步打开SCRIPT目录；");
                ImGui::BulletText(u8" - 第二步双击exe程序；");
                ImGui::Text(u8"SCRIPT说明：");
                ImGui::BulletText(u8" - 卧室嫩爹！");
                ImGui::BulletText(u8" - SUPER反弹！");
                ImGui::Text(u8"最后说明!");
            }
            ImGui::EndTabItem();
        }

        ImGui::EndTabBar();


    }

    ImGui::End();
    ImGui::EndFrame();
    ImGui::Render();
    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
    HRESULT result = pd3dDevice->EndScene();
    Helpers::HookFunction((PVOID*)(&oldEndSceneAdrs), hkEndScene);
    return result;
}

void checkError(bool state, const char* str = nullptr)
{
    if (state) return;
    char buffer[1024 * 2];
    sprintf(buffer, "发生异常： %s", str);
    MessageBoxA(NULL, buffer, NULL, MB_OK | MB_ICONHAND);
    exit(-1);
}

// 程序入口后的线程开始处
void init_d3d9(void* data)
{

    //AllocConsole();    
    //freopen("CON", "w", stdout);
    //SetConsoleTitleA("调试窗口");

    // 设置游戏的类名或者窗口标题，如果此函数被检测，可以更换其他方式获得窗口句柄。
    do
    {
        g_hWnd = Helpers::GetCurrentWindowHandle();
    } while (!g_hWnd);

    g_Direct3D9 = Direct3DCreate9(D3D_SDK_VERSION);

    checkError(g_Direct3D9, "Direct3DCreate9 失败！！");

    memset(&g_present, 0, sizeof(g_present));
    g_present.Windowed = TRUE;
    g_present.SwapEffect = D3DSWAPEFFECT_DISCARD;
    g_present.BackBufferFormat = D3DFMT_UNKNOWN;
    g_present.EnableAutoDepthStencil = TRUE;
    g_present.AutoDepthStencilFormat = D3DFMT_D16;

    HRESULT result = g_Direct3D9->CreateDevice(
        D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_present, &g_pd3dDevice
    );

    checkError(result == 0, "CreateDevice 失败！！");
    SELF_PTR* d3d9_tableVT = NULL;

    d3d9_tableVT = (SELF_PTR*)*(SELF_PTR*)g_pd3dDevice;
    oldResetAdrs = (Reset_t)(d3d9_tableVT[16]);
    oldEndSceneAdrs = (EndScene_t)(d3d9_tableVT[42]);

    //printf("开始创建 \t&oldResetAdrs     \t成功  \t地址=>  \t%016llX \t \n", (SELF_PTR)&oldResetAdrs);
    //printf("开始创建 \t&oldEndSceneAdrs  \t成功  \t地址=>  \t%016llX \t \n", (SELF_PTR)&oldEndSceneAdrs);

    Helpers::HookFunction((PVOID*)(&oldResetAdrs), hkReset);
    Helpers::HookFunction((PVOID*)(&oldEndSceneAdrs), hkEndScene);

    //oWndProc = (WNDPROC)SetWindowLongPtr(g_hWnd, WNDPROC_INDEX, (LONG_PTR)hkWndProc);

}

void unLoad()
{
    Helpers::UnHookFunction((PVOID*)(&oldResetAdrs), hkReset);
    Helpers::UnHookFunction((PVOID*)(&oldEndSceneAdrs), hkEndScene);
}


// 程序入口
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  reason_call, LPVOID lpReserved)
{
    switch (reason_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        DisableThreadLibraryCalls(hModule);
        ::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)init_d3d9, NULL, NULL, NULL);
        break;
    }
    case DLL_PROCESS_DETACH:
    {
        unLoad();
        break;
    }

    case DLL_THREAD_ATTACH: break;
    case DLL_THREAD_DETACH: break;

    }
    return TRUE;
}
